import soot.Body;
import soot.Local;
import soot.Scene;
import soot.SootClass;
import soot.SootMethod;
import soot.Unit;
import soot.options.Options;
import soot.toolkits.graph.ExceptionalUnitGraph;
import soot.toolkits.graph.UnitGraph;
import soot.util.Chain;
import apron.ApronException;

public class Main {

	/**
	 * @param args
	 * @throws ApronException
	 */
	public static void main(String[] args) throws ApronException {
		String classPath = "./";
		String className = "samples.Examples";
		String funcName = "example1";
		if(args.length == 3) {
			classPath = args[0];
			className = args[1];
			funcName = args[2];
			initializeSoot(classPath, className);
		}

		SootClass c = Scene.v().loadClassAndSupport(className);
		c.setApplicationClass();

		SootMethod m = c.getMethodByName(funcName);
		Body b = m.retrieveActiveBody();
		System.out.println("==== parsed function: ====\n" + b.toString()
				+ "\n======\n");
		Chain<Local> a = b.getLocals();

		// Build the CFG and run the analysis
		UnitGraph g = new ExceptionalUnitGraph(b);
		// new IntervalAnalysis(g, a);
		Analyzer k = new Analyzer(g, a);

		printResults(k, g);
		// new AnalysisTester(g);
	}

	private static void printResults(Analyzer k, UnitGraph g) {

		for (Unit u : g) {
			System.out.println("=================");
			System.out.println(u);
			System.out.println(">Flow After:   ");
			System.out.println(k.getFallFlowAfter(u));
			System.out.println(">Branch Flow After:   ");
			System.out.println(k.getBranchFlowAfter(u));

		}
	}
	
	private static void initializeSoot(String classpath, String classname) {
		soot.G.reset();
		Options sootOptions = Options.v();
		sootOptions.set_allow_phantom_refs(true);
		sootOptions.set_src_prec(Options.src_prec_java);
		sootOptions.set_output_format(Options.output_format_jimple);
		sootOptions.set_output_dir(".");
		sootOptions.set_soot_classpath(classpath);
		sootOptions.set_whole_program(true);
		sootOptions.set_verbose(false);
		sootOptions.classes().add(classname);
		sootOptions.set_keep_line_number(true);
	}
}